package com.api.util.repo.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class FactoryParams {

	private final Map<String, Object> map = new HashMap<String, Object>();

	private final Set<String> nullFields = new HashSet<String>();

	public void set(String key, Object value) {
		checkNotNull(key);

		if (value != null) {
			if (nullFields.contains(key)) {
				nullFields.remove(key);
			}
			map.put(key, value);
		} else {
			if (map.containsKey(key)) {
				map.remove(key);
			}
			nullFields.add(key);
		}
	}

	public <T> T get(String key) {
		checkNotNull(key);
		if (!map.containsKey(key) && !nullFields.contains(key)) {
			throw new IllegalStateException(String.format("Field '%s' does not exist", key));
		}

		@SuppressWarnings("unchecked")
		T value = (T) map.get(key);
		return value;
	}

	public boolean contains(String key) {
		checkNotNull(key);
		return map.containsKey(key) || nullFields.contains(key);
	}

	public void updateFields(FactoryParams params) {
		List<String> fields = params.getFields();
		for (String field : fields) {
			if (this.contains(field)) {
				this.set(field, params.get(field));
			} else {
				throw new IllegalStateException(String.format("Factory params does not contain field '%s'", field));
			}
		}
	}

	public List<String> getFields() {
		List<String> fields = new ArrayList<String>();
		fields.addAll(map.keySet());
		fields.addAll(nullFields);
		return fields;
	}

	private void checkNotNull(String key) {
		if (key == null) {
			throw new IllegalArgumentException("Key cannot be null");
		}
	}
}
